﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ProgrammerToolsKits.Comic.Interface;

using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Web.Http;

namespace ProgrammerToolsKits.Comic
{
    using ComicBookHashValue = System.String;
    using ComicBookPath = System.String;
    using Newtonsoft.Json;
    using ProgrammerToolsKits.Interface;

    public class ComicBuffer : INetworkService, IComicBuffer
    {
        #region Private
        //------------------------------------------------------------------------------------------------------

        private static HttpClient                   service                             = null;
        private static ICacheStorage                Buffer                              = null;
        private readonly IComicBook                 Book                                = null;
        private readonly IComicVolume               Volume                              = null;
        private readonly SynchronizationContext     Context                             = SynchronizationContext.Current;

        //下载目录为Pictures目录下

        private CacheMode                           Mode                                = CacheMode.NoCache;
        //------------------------------------------------------------------------------------------------------

        #endregion        

        static ComicBuffer()
        {
            Buffer = new CacheStorage();
            service = new HttpClient();
        }

        public ComicBuffer(CacheMode mode, IComicBook book, IComicVolume volume)
        {
            Mode = mode;
            Book = book;
            Volume = volume;
        }
        public ComicBuffer()
        {

        }

        async public void CacheThrumb()
        {
            Modal.ComicPage thrumb = new Modal.ComicPage()
            {
                Source = Book.Thrumb
            };
            await Buffer.CacheComicPage( Book, Volume, thrumb, await service.GetBufferAsync( new Uri( Book.Thrumb ) ) );
        }

        async public Task<BitmapImage> CacheBitmapImage(IComicPage page)
        {
            BitmapImage bi = null;
            var Path = Buffer.IComicPageMapping( Book, Volume, page );
            if (!Buffer.IsCache( Book, Volume, page ) )
            {
                switch ( Mode )
                {
                    case CacheMode.NoCache:
                        return new BitmapImage( new Uri( page.Source ) );
                    default:
                        Context.Post( (o) => o = new BitmapImage(), bi );
                        break;
                }
                var buffer = await service.GetBufferAsync( new Uri( page.Source ) );
                using ( var ms = new InMemoryRandomAccessStream() )
                {
                    await ms.WriteAsync( buffer );
                    await bi.SetSourceAsync( ms );
                    await Buffer.CacheComicPage( Book, Volume, page, buffer );
                }
                return bi;
            }
            else
            {
                return new BitmapImage( new Uri( Path ) );
            }
        }

        #region InternalCache
        interface ICacheStorage
        {
            string IComicBookMapping(IComicBook book);
            string IComicVolumeMapping(IComicBook book, IComicVolume volume);
            string IComicPageMapping(IComicBook book, IComicVolume volume, IComicPage page);
            void CacheComicBook(IComicBook book);
            void CacheComicVolume(IComicBook book, IComicVolume volume);
            Task CacheComicPage(IComicBook book, IComicVolume volume, IComicPage page, IBuffer buffer);
            bool IsCache(IComicBook book, IComicVolume volume, IComicPage page);
            bool IsCache(IComicBook book, IComicVolume volume);
            bool IsCache(IComicBook book);
        }
        class CacheStorage : ICacheStorage
        {
            Dictionary<ComicBookHashValue,ComicBookPath>                CacheDictionary;
            StorageFolder                                               CacheFolder;
            StorageFile                                                 CacheFile;

            public CacheStorage()
            {
                Task t = new Task( async () =>
                 {
                     var Path = System.IO.Path.Combine( ApplicationData.Current.LocalFolder.Path, "Comic" );
                     if ( ApplicationData.Current.LocalSettings.Values.TryGetValue( "CacheFolder", out var SettingFolder ) )
                     {
                         CacheFolder = await StorageFolder.GetFolderFromPathAsync( SettingFolder.ToString() );
                     }
                     else
                     {
                         
                         if(!System.IO.Directory.Exists(Path))
                         {
                             System.IO.Directory.CreateDirectory( Path );
                         }
                         CacheFolder = await StorageFolder.GetFolderFromPathAsync( Path );
                     }

                     if ( System.IO.File.Exists( System.IO.Path.Combine(Path,"CacheDictionary.cp" )))
                     {
                         CacheFile = await CacheFolder.GetFileAsync( "CacheDictionary.cp" );
                         var Json = await FileIO.ReadTextAsync( CacheFile );
                         CacheDictionary = JsonConvert.DeserializeObject<Dictionary<ComicBookHashValue, ComicBookHashValue>>( Json );
                     }
                     else
                     {
                         CacheDictionary = new Dictionary<ComicBookHashValue, ComicBookHashValue>( 8 );
                         CacheFile = await CacheFolder.CreateFileAsync( "CacheDictionary.cp" );
                     }
                 } );
                t.Start();
            }

            #region MappingPath
            public string IComicBookMapping(IComicBook book)
            {
                return System.IO.Path.Combine( CacheFolder.Path, book.Hash );
            }
            public string IComicVolumeMapping(IComicBook book, IComicVolume volume)
            {
                return System.IO.Path.Combine( IComicBookMapping( book ), volume.Hash );
            }
            public string IComicPageMapping(IComicBook book, IComicVolume volume, IComicPage page)
            {
                return System.IO.Path.Combine( IComicVolumeMapping( book, volume ), page.Hash );
            }
            #endregion

            #region Interface
            /// <summary>
            /// 当第一次缓冲ComicBook时将会创建缓冲目录，并将对应的信息保存到设置中
            /// </summary>
            /// <param name="book"></param>
            async public void CacheComicBook(IComicBook book)
            {
                if ( !CacheDictionary.TryGetValue( book.Hash, out var Path ) )
                {
                    Path = IComicBookMapping( book );
                    CacheDictionary.Add( book.Hash, Path );
                    System.IO.Directory.CreateDirectory( Path );
                    var json = JsonConvert.SerializeObject( CacheDictionary );
                    await FileIO.WriteTextAsync( CacheFile, json );
                }
            }

            /// <summary>
            /// 缓冲图片页
            /// </summary>
            /// <param name="page"></param>
            /// <param name="buffer"></param>
            async public Task CacheComicPage(IComicBook book, IComicVolume volume, IComicPage page, IBuffer buffer)
            {
                var Path = IComicPageMapping( book, volume, page );
                var folder = await CacheFolder.CreateFolderAsync( IComicVolumeMapping( book, volume ) );
                var file = await folder.CreateFileAsync( Path );
                await FileIO.WriteBufferAsync( file, buffer );
            }

            /// <summary>
            /// 当第一次缓冲Volume的时候创建对应的目录
            /// </summary>
            /// <param name="book"></param>
            /// <param name="volume"></param>
            async public void CacheComicVolume(IComicBook book, IComicVolume volume)
            {
                var folder = await CacheFolder.GetFolderAsync( IComicBookMapping( book ) ) ??
                    await CacheFolder.CreateFolderAsync( IComicBookMapping( book ) );
                var v_folder = await folder.GetFolderAsync( IComicVolumeMapping( book, volume ) ) ??
                    await folder.CreateFolderAsync( IComicVolumeMapping( book, volume ) );
            }


            public bool IsCache(IComicBook book, IComicVolume volume, IComicPage page)
            {
                
                return System.IO.File.Exists( IComicPageMapping( book, volume, page ) );
                ;
            }

            public bool IsCache(IComicBook book, IComicVolume volume)
            {
                var v = System.IO.Directory.Exists( IComicVolumeMapping( book, volume ) );
                return v && IsCache( book );
            }

            public bool IsCache(IComicBook book)
            {
                return CacheDictionary.TryGetValue( book.Hash, out var Path ) &&
                    System.IO.Directory.Exists( IComicBookMapping( book ));
            }
        }
        #endregion

        #endregion


        #region INetworkService
        async public Task<string> GetHtml(string address)
        {
            return await service.GetStringAsync( new Uri( address ) );
        }
        #endregion

        public INetworkService Service { get => this; }
    }
}
